﻿using System;
using System.Collections.Generic;
using Mockery.Core.CommonContainer;

namespace Mockery.Core
{
    /// <summary>
    /// TypeCache stores mocked and stubbed instances in the course 
    /// a test.
    /// </summary>
    public class TypeCache : Dictionary<Type, object>, ITypeCache
    {
        private readonly ICommonContainerBuilder _commonContainerBuilder;
        public TypeCache(ICommonContainerBuilder commonContainerBuilder)
        {
            _commonContainerBuilder = commonContainerBuilder;
        }
        #region ITypeCache Members

        /// <summary>
        /// Adds a mocked type to the collection
        /// </summary>
        /// <typeparam name="TType">The type being stored</typeparam>
        /// <param name="value">The associated instance being stored</param>
        /// <returns>the instance reference</returns>
        public TType AddMockedType<TType>(TType value)
        {
            try
            {
                Add(typeof (TType), value);
            }
            catch( ArgumentException argumentException)
            {
                throw new DuplicateMockException(
                    string.Format("A duplicate mock of type '{0}' was attempted to be added", typeof(TType).Name),
                    argumentException);
            }

            return value;
        }

        /// <summary>
        /// Returns a stored mock or stub by keyed type
        /// </summary>
        /// <typeparam name="TType">type key</typeparam>
        /// <returns>stored instance</returns>
        public TType GetMockedType<TType>()
        {
            try
            {
                return (TType) this[typeof (TType)];
            }
            catch( KeyNotFoundException keyNotFoundException)
            {
                throw new MissingMockException(
                    string.Format("A mock of type '{0}' was not found in the configured types", typeof (TType).Name),
                    keyNotFoundException);
            }
        }

        /// <summary>
        /// Registers the stored types with the stored instance.
        /// </summary>
        /// <returns>a container builder loaded with the registered types</returns>
        public ICommonContainerBuilder RegisterTypes()
        {
            
            foreach (var key in Keys)
                _commonContainerBuilder.RegisterInstance(key, this[key]);

            return _commonContainerBuilder;
        }

        #endregion
    }
}
